package schema.ext;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

import javax.xml.bind.JAXBException;

import jhunter.common.exception.ConfigException;
import jhunter.dao.EntityContainer;
import jhunter.dao.EntityExt;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import schema.Node;
import schema.io.ModuleXmlLoader;
import schema.vo.module.Action;
import schema.vo.module.Actions;
import schema.vo.module.EasyForm;
import schema.vo.module.Entities;
import schema.vo.module.Entity;
import schema.vo.module.Module;
import schema.vo.module.Service;
import schema.vo.module.Services;

public class ModuleExt extends Node {

	private Logger logger = LoggerFactory.getLogger(ModuleExt.class);

	private Module module;

	private ModuleXmlLoader moduleXmlLoader = new ModuleXmlLoader();

	private Map<PathInfo, ActionExt> actionMap = new ConcurrentHashMap<PathInfo, ActionExt>();

	private Map<String, Object> serviceMap = new ConcurrentHashMap<String, Object>();
	
	private Set<String> moduleClassSet = new ConcurrentSkipListSet<String>();

	private String path;

	private boolean needReload = false;

	private ClassLoader instanceClassLoader;

	public void reload() {
		load(path);
		needReload = false;
	}

	public void load(String path) {
		this.path = path;
		moduleClassSet.clear();
		instanceClassLoader = ((AppExt) this.getParent())
				.createNewClassLoader();
		try {

			module = (Module) moduleXmlLoader.getUnmarshal().unmarshal(
					setFileAndReturnStream(path));
		} catch (JAXBException e) {
			e.printStackTrace();
			throw new ConfigException(e);
		}
		initEntity();
		/**
		 * 先service后Action service是容器内单例的,action是每次都new
		 */
		initServiceMap();
		initActionMap();
		setContextPath(module.getBaseContext());
	}

	private void initEntity() {
		Entities ents = module.getEntities();
		if(ents != null) {
			List<Entity> list = ents.getEntity();
			AppExt appExt = (AppExt)getParent();
			for (Entity entity : list) {
				EntityContainer container = appExt.getAppContext().getEntityContainer();
				EntityExt en = new EntityExt(container, entity);
				container.registEntityExt(en);
				if(ents.isSynchronized()) {
					appExt.getAppContext().getSchemaGenerator().create(en);
				}
			}
		}
	}

	private void initServiceMap() {
		serviceMap.clear();
		Services services = module.getServices();
		if (services == null) {
			return;
		}
		List<Service> list = services.getService();
		for (int i = 0; i < list.size(); i++) {
			Service s = list.get(i);
			ServiceExt se = new ServiceExt(this, s);
			serviceMap.put(s.getClazz(), se.getServiceInstance());
			moduleClassSet.add(s.getClazz());
		}
	}

	public void initActionMap() {
		actionMap.clear();
		Actions acs = module.getActions();
		if (acs == null) {
			return;
		}
		List<Action> list = acs.getAction();
		for (Action action : list) {
			ActionExt ae = new ActionExt(this, action);
			actionMap.put(ae.getPathInfo(), ae);
			logger.debug("Path:" + ae.getPathInfo().toString());
			moduleClassSet.add(action.getClazz());
		}
	}

	public Module getModule() {
		return module;
	}

	public void setModule(Module module) {
		this.module = module;
	}

	public EasyForm getFormByName(String easyForm) {
		// TODO Auto-generated method stub
		return null;
	}

	public Map<PathInfo, ActionExt> getActionMap() {
		return actionMap;
	}

	public void setActionMap(Map<PathInfo, ActionExt> actionMap) {
		this.actionMap = actionMap;
	}

	@Override
	protected ClassLoader getClassLoader() {
		AppExt app = (AppExt) super.getParent();
		return app.getClassLoader();
	}

	public boolean isNeedReload() {
		return needReload;
	}

	public void setNeedReload(boolean needReload) {
		this.needReload = needReload;
	}

	public Set<String> getModuleClassSet() {
		return moduleClassSet;
	}

	public void setModuleClassSet(Set<String> moduleClassSet) {
		this.moduleClassSet = moduleClassSet;
	}

	public Map<String, Object> getServiceMap() {
		return serviceMap;
	}

	public void setServiceMap(Map<String, Object> serviceMap) {
		this.serviceMap = serviceMap;
	}

	public ClassLoader getInstanceClassLoader() {
		return instanceClassLoader;
	}

	public void setInstanceClassLoader(ClassLoader instanceClassLoader) {
		this.instanceClassLoader = instanceClassLoader;
	}
}
